#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dml/dml.h>
#include <extensions/gldml.h>
#include "engine.h"
#include "matrix4x4f.h"

void CalculateTangents(s_mesh *mesh)
{
    
}


void drawobject(s_mesh *mesh)
{
    int a,b,c,ta,tb,tc,na,nb,nc;
    int i;

    glBegin(GL_TRIANGLES);

    for (i=0;i<mesh->numfaces;i++) 
    {
        // get a,b,c, indices
        a=mesh->face[i].a;b=mesh->face[i].b;c=mesh->face[i].c;
        ta=mesh->face[i].ta;tb=mesh->face[i].tb;tc=mesh->face[i].tc;
        na=mesh->face[i].na;nb=mesh->face[i].nb;nc=mesh->face[i].nc;

        // defineer de 3 vertices van de triangle
        glNormal3f(mesh->normals[na].x, mesh->normals[na].y,mesh->normals[na].z);
        glTexCoord2f(mesh->tvertex[ta].u, mesh->tvertex[ta].v);
        glVertex3f(mesh->vertex[a].x,mesh->vertex[a].y,mesh->vertex[a].z);

        glNormal3f(mesh->normals[nb].x, mesh->normals[nb].y,mesh->normals[nb].z);
        glTexCoord2f(mesh->tvertex[tb].u, mesh->tvertex[tb].v);
        glVertex3f(mesh->vertex[b].x,mesh->vertex[b].y,mesh->vertex[b].z);

        glNormal3f(mesh->normals[nc].x, mesh->normals[nc].y,mesh->normals[nc].z);
        glTexCoord2f(mesh->tvertex[tc].u, mesh->tvertex[tc].v);
        glVertex3f(mesh->vertex[c].x,mesh->vertex[c].y,mesh->vertex[c].z);
    }
    glEnd();
}


void LoadMesh(char *fn,s_mesh *mesh)
{
    FILE *f;
    char str[256],id[16];
    float x,y,z;
    int a,b,c,ta,tb,tc,na,nb,nc;


    mesh->numvertices=0;
    mesh->numtvertices=0;
    mesh->numfaces=0;
    mesh->numnormals=0;

    // Count verts/faces for allocation
    f=fopen(fn,"rt");
    do 
    {
        fgets(str,256,f);       // lees regel in
        sscanf(str,"%s",id);    // lees id uit string
        if (!strcmp(id,"v")) mesh->numvertices++;
        if (!strcmp(id,"vt")) mesh->numtvertices++;
        if (!strcmp(id,"f")) mesh->numfaces++;
        if (!strcmp(id,"vn")) mesh->numnormals++;
    } while(!feof(f));
    fclose(f);

    mesh->vertex=(s_vertex*)malloc(mesh->numvertices*sizeof(s_vertex));
    mesh->tvertex=(s_tvertex*)malloc(mesh->numtvertices*sizeof(s_tvertex));
    mesh->face=(s_face*)malloc(mesh->numfaces*sizeof(s_face));
    mesh->normals=(s_normals*)malloc(mesh->numnormals*sizeof(s_normals));
    
    //tangend space to calculate different shaders
    mesh->tangents=(s_tangents*)malloc(mesh->numvertices*sizeof(s_tangents));

    // Read object
    mesh->numvertices=0;
    mesh->numtvertices=0;
    mesh->numfaces=0;
    mesh->numnormals=0;

    f=fopen(fn,"rt");
    
    do 
    {

        fgets(str,256,f);       // lees regel in

        sscanf(str,"%s",id);    // lees id uit string
        printf("ID is: %s\n",id);

        // LEES VERTEX
        if (!strcmp(id,"v")) {  // als id gelijk is aan 'v'
            sscanf(str,"v %f %f %f",&x,&y,&z);   // lees rest van de regel x,y,z
            printf("VERTEX: %f %f %f\n",x,y,z);
            mesh->vertex[mesh->numvertices].x=x/10;
            mesh->vertex[mesh->numvertices].y=y/10;
            mesh->vertex[mesh->numvertices].z=z/10;
            mesh->numvertices++;
        }

        // LEES TEXTURED VERTEX (u,v)
        if (!strcmp(id,"vt")) {  // als id gelijk is aan 'v'
            sscanf(str,"vt %f %f %f",&x,&y,&z);   // lees rest van de regel x,y,z
            printf("TVERTEX: %f %f %f\n",x,y,z);
            mesh->tvertex[mesh->numtvertices].u=x;
            mesh->tvertex[mesh->numtvertices].v=1-y;
            mesh->numtvertices++;
        }

        // LEES NORMALS (x,y,z)

        if (!strcmp(id,"vn")) {  // als id gelijk is aan 'v'
            sscanf(str,"vn %f %f %f",&x,&y,&z);   // lees rest van de regel x,y,z
            printf("NORMAL: %f %f %f\n",x,y,z);
            mesh->normals[mesh->numnormals].x=x;
            mesh->normals[mesh->numnormals].y=y;
            mesh->normals[mesh->numnormals].z=z;
            mesh->numnormals++;
        }

        // LEES FACES
        if (!strcmp(id,"f")) {  // als id gelijk is aan 'v'
            sscanf(str,"f %d/%d/%d %d/%d/%d %d/%d/%d",&a,&ta,&na,&b,&tb,&nb,&c,&tc,&nc);   // lees rest van de regel x,y,z
            printf("FACE: %d %d %d\n",a,b,c);
            mesh->face[mesh->numfaces].a=a-1;
            mesh->face[mesh->numfaces].b=b-1;
            mesh->face[mesh->numfaces].c=c-1;
            mesh->face[mesh->numfaces].ta=ta-1;
            mesh->face[mesh->numfaces].tb=tb-1;
            mesh->face[mesh->numfaces].tc=tc-1;
            mesh->face[mesh->numfaces].na=na-1;
            mesh->face[mesh->numfaces].nb=nb-1;
            mesh->face[mesh->numfaces].nc=nc-1;
            mesh->numfaces++;
        }

    }while(!feof(f));  // zolang niet einde file
    fclose(f);
    
    //Init Vectors before calculations.
    for( int i = 0; i < mesh->numvertices; ++i )
    {
        mesh->tangents[i].g_vTangents  = vector3f( 1.0f, 0.0f, 0.0f );
        mesh->tangents[i].g_vBiNormals = vector3f( 0.0f, 1.0f, 0.0f );
        mesh->tangents[i].g_vNormals   = vector3f( 0.0f, 0.0f, 1.0f );
    }
}

void DeleteMesh(s_mesh *mesh)
{
    mesh->numvertices=0;
    mesh->numtvertices=0;
    mesh->numfaces=0;
    free(mesh->vertex);
    free(mesh->tvertex);
    free(mesh->face);
}

void createTangentSpaceVectors( vector3f *v1,
                                vector3f *v2,
                                vector3f *v3,
                                float v1u, float v1v,
                                float v2u, float v2v,
                                float v3u, float v3v,
                                vector3f *vTangent,
                                vector3f *vBiNormal,
                                vector3f *vNormal )
{
    // Create edge vectors from vertex 1 to vectors 2 and 3.
    vector3f vDirVec_v2_to_v1 = *v2 - *v1;
    vector3f vDirVec_v3_to_v1 = *v3 - *v1;

    // Create edge vectors from the texture coordinates of vertex 1 to vector 2.
    float vDirVec_v2u_to_v1u = v2u - v1u;
    float vDirVec_v2v_to_v1v = v2v - v1v;

    // Create edge vectors from the texture coordinates of vertex 1 to vector 3.
    float vDirVec_v3u_to_v1u = v3u - v1u;
    float vDirVec_v3v_to_v1v = v3v - v1v;

    float fDenominator = vDirVec_v2u_to_v1u * vDirVec_v3v_to_v1v -
                         vDirVec_v3u_to_v1u * vDirVec_v2v_to_v1v;

    if( fDenominator < 0.0001f && fDenominator > -0.0001f )
    {
        // We're too close to zero and we're at risk of a divide-by-zero!
        // Set the tangent matrix to the identity matrix and do nothing.
        *vTangent  = vector3f( 1.0f, 0.0f, 0.0f );
        *vBiNormal = vector3f( 0.0f, 1.0f, 0.0f );
        *vNormal   = vector3f( 0.0f, 0.0f, 1.0f );
    }
    else
    {
        // Calculate and cache the reciprocal value
        float fScale1 = 1.0f / fDenominator;

        vector3f T;
        vector3f B;
        vector3f N;

        T = vector3f((vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.x - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.x) * fScale1,
                     (vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.y - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.y) * fScale1,
                     (vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.z - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.z) * fScale1);

        B = vector3f((-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.x + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.x) * fScale1,
                     (-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.y + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.y) * fScale1,
                     (-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.z + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.z) * fScale1);

        // The normal N is calculated as the cross product between T and B
        N = crossProduct( T, B );

        // Calculate and cache the reciprocal value
        float fScale2 = 1.0f / ((T.x * B.y * N.z - T.z * B.y * N.x) +
                                (B.x * N.y * T.z - B.z * N.y * T.x) +
                                (N.x * T.y * B.z - N.z * T.y * B.x));

        //
        // Use the temporary T (Tangent), (B) Binormal, and N (Normal) vectors
        // to calculate the inverse of the tangent matrix that they represent.
        // The inverse of the tangent matrix is what we want since we need that
        // to transform the light's vector into tangent-space.
        //

        (*vTangent).x =   crossProduct( B, N ).x * fScale2;
        (*vTangent).y = -(crossProduct( N, T ).x * fScale2);
        (*vTangent).z =   crossProduct( T, B ).x * fScale2;
        (*vTangent).normalize();

        (*vBiNormal).x = -(crossProduct( B, N ).y * fScale2);
        (*vBiNormal).y =   crossProduct( N, T ).y * fScale2;
        (*vBiNormal).z = -(crossProduct( T, B ).y * fScale2);
        (*vBiNormal).normalize();

        (*vNormal).x =   crossProduct( B, N ).z * fScale2;
        (*vNormal).y = -(crossProduct( N, T ).z * fScale2);
        (*vNormal).z =   crossProduct( T, B ).z * fScale2;
        (*vNormal).normalize();

        //
        // NOTE: Since the texture-space of Direct3D and OpenGL are laid-out
        //       differently, a single normal map can't look right in both
        //       unless you make some adjustments somewhere.
        //
        //       You can adjust or fix this problem in three ways:
        //
        //       1. Create two normal maps: one for OpenGL and one for Direct3D.
        //       2. Flip the normal map image over as you load it into a texture
        //          object.
        //       3. Flip the binormal over when computing the tangent-space
        //          matrix.
        //
        // Since the normal map used by this sample was created for Direct3D,
        // I've decided to simply flip the binormal.
        //
        *vBiNormal = *vBiNormal * -1.0f;
    }
}

void CalculateBumpMapping(s_mesh* mesh)
{
    vector3f v1;
    vector3f v2;
    vector3f v3;
    vector3f vTangent;
    vector3f vBiNormal;
    vector3f vNormal;

    //
    // For each triangle face defined in the vertex array, compute a tangent matrix
    // for each of the four vertices that define it.
    //

    for( int i = 0; i < mesh->numvertices; i += 3 ) // Use += 3 to process 1 face at a time
    {
        //

        v1 = vector3f(mesh->vertex[i].x,mesh->vertex[i].y,mesh->vertex[i].z);
        v2 = vector3f(mesh->vertex[i+2].x,mesh->vertex[i+2].y,mesh->vertex[i+3].z);
        v3 = vector3f(mesh->vertex[i+1].x,mesh->vertex[i+1].y,mesh->vertex[i+1].z);

        createTangentSpaceVectors( &v1,&v2,&v3,
                                   mesh->tvertex[i].u, mesh->tvertex[i].v,
                                   mesh->tvertex[i+3].u, mesh->tvertex[i+3].v,
                                   mesh->tvertex[i+1].u, mesh->tvertex[i+1].v,
                                   &vTangent, &vBiNormal, &vNormal );
        mesh->tangents[i].g_vTangents  = vTangent;
        mesh->tangents[i].g_vBiNormals = vBiNormal;
        mesh->tangents[i].g_vNormals   = vNormal;


        v1 = vector3f(mesh->vertex[i+1].x,mesh->vertex[i+1].y,mesh->vertex[i+1].z);
        v2 = vector3f(mesh->vertex[i].x,mesh->vertex[i].y,mesh->vertex[i].z);
        v3 = vector3f(mesh->vertex[i+2].x,mesh->vertex[i+2].y,mesh->vertex[i+2].z);

        createTangentSpaceVectors( &v1,&v2,&v3,
                                   mesh->tvertex[i+1].u, mesh->tvertex[i+1].v,
                                   mesh->tvertex[i].u, mesh->tvertex[i].v,
                                   mesh->tvertex[i+2].u, mesh->tvertex[i+2].v,
                                   &vTangent, &vBiNormal, &vNormal );

        mesh->tangents[i+1].g_vTangents  = vTangent;
        mesh->tangents[i+1].g_vBiNormals = vBiNormal;
        mesh->tangents[i+1].g_vNormals   = vNormal;


        v1 = vector3f(mesh->vertex[i+2].x,mesh->vertex[i+2].y,mesh->vertex[i+2].z);
        v2 = vector3f(mesh->vertex[i+1].x,mesh->vertex[i+1].y,mesh->vertex[i+1].z);
        v3 = vector3f(mesh->vertex[i].x,mesh->vertex[i].y,mesh->vertex[i+3].z);

        createTangentSpaceVectors( &v1,&v2,&v3,
                                   mesh->tvertex[i+2].u, mesh->tvertex[i+2].v,
                                   mesh->tvertex[i+1].u, mesh->tvertex[i+1].v,
                                   mesh->tvertex[i+3].u, mesh->tvertex[i+3].v,
                                   &vTangent, &vBiNormal, &vNormal );

        mesh->tangents[i+2].g_vTangents  = vTangent;
        mesh->tangents[i+2].g_vBiNormals = vBiNormal;
        mesh->tangents[i+2].g_vNormals   = vNormal;
    }
}

void CreateBumpTexture(s_bitmap normal, s_bitmap texture, int* textureid, int* normalid)
{
    int normal_id, texture_id;
    //
    // Load the normal map...
    //
    //AUX_RGBImageRec *pTextureImage = auxDIBImageLoad(fn_normal);
    normal_id = DML_CreateTextureGL(normal);
    glBindTexture( GL_TEXTURE_2D, normal_id );
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_ARB);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, normal.width, normal.height, 0,GL_RGB, GL_UNSIGNED_BYTE, normal.data );

    //
    // Load the base texture
    //
    //pTextureImage = auxDIBImageLoad(fn_texture);
    texture_id = DML_CreateTextureGL(texture);
    glBindTexture( GL_TEXTURE_2D, texture_id );
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_ARB);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, texture.width, texture.height, 0,GL_RGB, GL_UNSIGNED_BYTE, texture.data );
    
    normalid  = &normal_id;
    textureid = &texture_id;
}


bool CheckOpenGLExtensions()
{
    char *ext = (char*)glGetString( GL_EXTENSIONS );

    if( strstr( ext, "GL_ARB_multitexture" ) == NULL )
    {
        MessageBox(NULL,"GL_ARB_multitexture extension was not found","ERROR",MB_OK|MB_ICONEXCLAMATION);
        return false;
    }
    else
    {
        glActiveTexture       = (PFNGLCLIENTACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
        glMultiTexCoord2f     = (PFNGLMULTITEXCOORD2FPROC)wglGetProcAddress("glMultiTexCoord2f");
        glClientActiveTexture = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTexture");

        if( !glActiveTexture || !glMultiTexCoord2f || !glClientActiveTexture )
        {
            MessageBox(NULL,"One or more GL_ARB_multitexture functions were not found","ERROR",MB_OK|MB_ICONEXCLAMATION);
            return false;
        }
    }
    
    //
    // GL_EXT_texture_env_combine
    //

    if( strstr( ext, "GL_EXT_texture_env_combine" ) == NULL )
    {
        MessageBox(NULL,"GL_EXT_texture_env_combine extension was not found",
            "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return false;
    }
}

vector3f scaleAndBiasVectorAsRGBColor( vector3f* vVector )
{
    vector3f vScaledAndBiasedVector;

    vScaledAndBiasedVector.x = ((*vVector).x * 0.5f) + 0.5f;
    vScaledAndBiasedVector.y = ((*vVector).y * 0.5f) + 0.5f;
    vScaledAndBiasedVector.z = ((*vVector).z * 0.5f) + 0.5f;

    return vScaledAndBiasedVector;
}


void RenderModelWithBump(s_mesh *mesh, int texture_normal, int texture, int light)
{
    //
    // Render a Dot3 bump mapped cube...
    //

    //
    // STAGE 0
    //
    // Use GL_DOT3_RGB_EXT to find the dot-product of (N.L), where N is
    // stored in the normal map, and L is passed in as the PRIMARY_COLOR
    // using the standard glColor3f call.
    //

    glActiveTexture(GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, texture_normal);
    glEnable(GL_TEXTURE_2D);

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);      // Perform a Dot3 operation...
    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_EXT);

    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);           // between the N (of N.L) which is stored in a normal map texture...
    glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);

    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); // with the L (of N.L) which is stored in the vertex's diffuse color.
    glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);

    //
    // STAGE 1
    //
    // Modulate the base texture by N.L calculated in STAGE 0.
    //

    glActiveTexture(GL_TEXTURE1);
    glBindTexture (GL_TEXTURE_2D, texture);
    glEnable(GL_TEXTURE_2D);

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);  // Modulate...
    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);

    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
    glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);    // the color argument passed down from the previous stage (stage 0) with...

    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
    glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);    // the texture for this stage with.

    //
    // Transform the light's position from eye-space to object-space
    //

    vector3f vLightPosES;    // Light position (in eye-space)
    vector3f vLightPosOS;    // Light position (in object-space)
    vector3f vVertToLightOS; // L vector of N.L (in object-space)
    vector3f vVertToLightTS; // L vector of N.L (in tangent-space)

    // Get the light's current position, which is in eye-space.
    float fLightsPosition[4];
    glGetLightfv( GL_LIGHT0, GL_POSITION, fLightsPosition );
    vLightPosES.x = fLightsPosition[0];
    vLightPosES.y = fLightsPosition[1];
    vLightPosES.z = fLightsPosition[2];

    // Transform the light's position from eye-space into object-space
    matrix4x4f modelViewMatrix;
    matrix4x4f modelViewMatrixInverse;

    glGetFloatv(GL_MODELVIEW_MATRIX, &modelViewMatrix.m[0] );

    modelViewMatrixInverse = matrix4x4f::invertMatrix( &modelViewMatrix );
    vLightPosOS = vLightPosES;
    modelViewMatrixInverse.transformPoint( &vLightPosOS );

    //
    // Now, render our textured test cube, which consists of 6 quads...
    //

    vector3f vCurrentVertex;

    glBegin( GL_TRIANGLES );
    {
        for( int i = 0; i < mesh->numvertices; ++i )
        {
            vCurrentVertex.x = mesh->vertex[i].x;
            vCurrentVertex.y = mesh->vertex[i].y;
            vCurrentVertex.z = mesh->vertex[i].z;

            glMultiTexCoord2f( GL_TEXTURE0, mesh->tvertex[i].u, mesh->tvertex[i].v );
            glMultiTexCoord2f( GL_TEXTURE1, mesh->tvertex[i].u, mesh->tvertex[i].v );

            //
            // For each vertex, rotate L (of N.L) into tangent-space and
            // pass it into OpenGL's texture blending system by packing it
            // into the glVertex3f for that vertex.
            //

            vVertToLightOS = vLightPosOS - vCurrentVertex;
            vVertToLightOS.normalize();

            //
            // Build up an inverse tangent-space matrix using the Tangent,
            // Binormal, and Normal calculated for the current vertex and
            // then use it to transform our L vector (of N.L), which is in
            // object-space, into tangent-space.
            //
            // A tangent matrix is of the form:
            //
            // |Tx Bx Nx 0|
            // |Ty By Ny 0|
            // |Tz Bz Nz 0|
            // |0  0  0  1|
            //
            // Note: Our vectors have already been inverted, so there is no
            // need to invert our tangent matrix once we build it up.
            //

            //                                          Tangent                         Binormal                         Normal
            matrix4x4f invTangentMatrix(mesh->tangents[i].g_vTangents.x, mesh->tangents[i].g_vBiNormals.x, mesh->tangents[i].g_vNormals.x, 0.0f,
                                        mesh->tangents[i].g_vTangents.y, mesh->tangents[i].g_vBiNormals.y, mesh->tangents[i].g_vNormals.y, 0.0f,
                                        mesh->tangents[i].g_vTangents.z, mesh->tangents[i].g_vBiNormals.z, mesh->tangents[i].g_vNormals.z, 0.0f,
                                        0.0f,             0.0f,              0.0f,            1.0f );

            vVertToLightTS = vVertToLightOS;
            invTangentMatrix.transformVector( &vVertToLightTS );

            //
            // Last but not least, we must scale and bias our L vector
            // before passing it as a vertex color since colors have a
            // clamped range of [0,1]. If we don't do this any negative
            // components of our L vector will get clamped and the vector
            // will be wrong. Of course, the hardware assumes that we are
            // going to do this, so it will simply decode the original
            // vector back out by reversing the scale and bias we've
            // performed here.

            vector3f vVertToLightTS_scaledAndBiased = scaleAndBiasVectorAsRGBColor( &vVertToLightTS );
            glColor3f( vVertToLightTS_scaledAndBiased.x,vVertToLightTS_scaledAndBiased.y,vVertToLightTS_scaledAndBiased.z );
            glNormal3f( mesh->normals[i].x, mesh->normals[i].y, mesh->normals[i].z );
            glVertex3f( vCurrentVertex.x, vCurrentVertex.y, vCurrentVertex.z );
            
        }
    }
    glEnd();
    
    //
    // Reset texture unit state
    //

    glActiveTexture(GL_TEXTURE0);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glDisable(GL_TEXTURE_3D_EXT);
    glDisable(GL_TEXTURE_CUBE_MAP_ARB);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
    glDisable(GL_TEXTURE_GEN_R);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glActiveTexture(GL_TEXTURE1);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glDisable(GL_TEXTURE_3D_EXT);
    glDisable(GL_TEXTURE_CUBE_MAP_ARB);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
    glDisable(GL_TEXTURE_GEN_R);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    //
    // Render a small white sphere to mark the point light's position...
    //

    glDisable( GL_LIGHTING );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    //glTranslatef( 0.0f, 0.0f, g_fDistance );
    //glTranslatef( g_lightPosition[0], g_lightPosition[1], g_lightPosition[2] );

    glColor3f( 1.0f, 1.0f, 1.0f );
    //renderSolidSphere( 0.05f, 8, 8 );

    glEnable( GL_LIGHTING );
}

